﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using TinyUtil;

namespace MebAppInstaller
{
    public partial class DownloadForm : Form
    {
        private DownloadResult Result;
        public bool AllCompleted;
        string dir;
        private string urlfmt;
        private string[] files;
        private int filesDownload;
        private AutoResetEvent wh = new AutoResetEvent(false);
        public DownloadForm()
        {
            InitializeComponent();
            this.Load += DownloadForm_Load;
            this.StartPosition = FormStartPosition.CenterScreen;
            this.button1.Enabled = false;
        }

        private void DownloadForm_Load(object sender, EventArgs e)
        {
            FileUtil.Mkdir(Path.Combine(dir, "temp"));
            new Thread(() =>
            {
                Thread.Sleep(1000);
                for (int i = 0; i < files.Length; i++)
                {
                    filesDownload++;
                    try
                    {
                        this.Invoke(new Action(() =>
                        {
                            this.label2.Text = "第" + filesDownload + "个/共" + files.Length + "个 " + files[i];
                        }));
                    }
                    catch { }
                    var tempFileName = Path.Combine(dir, "temp", Path.GetRandomFileName());
                    WebClient client = new WebClient();
                    client.DownloadProgressChanged += Client_DownloadProgressChanged;
                    client.DownloadFileCompleted += Client_DownloadFileCompleted;
                    var tempFile = new TempFile(Path.Combine(dir, tempFileName), Path.Combine(dir, files[i]));
                    var hash = GetFileMd5(Environment.CurrentDirectory, tempFile.FileName);
                    var url = new Uri(string.Format(urlfmt, files[i], hash));
                    client.DownloadFileAsync(url, tempFile.TempFileName, tempFile);
                    wh.WaitOne();
                    if (Result == DownloadResult.Error)
                    {
                        this.DialogResult = DialogResult.Abort;
                        CloseForm();
                        return;
                    }
                    else
                        this.DialogResult = DialogResult.OK;
                    client.DownloadFileCompleted -= Client_DownloadFileCompleted;
                    client.DownloadProgressChanged -= Client_DownloadProgressChanged;
                    client.Dispose();
                }
                AllCompleted = true;
                CloseForm();
            }).Start();
        }

        private string GetFileMd5(string dir, string fileName)
        {
            var appZip = Path.Combine(dir, "app.zip");
            if (File.Exists(appZip))
            {
                return ZipHelper.FileMd5(appZip, fileName);
            }
            return "00000000000000000000000000000000";
        }
        private void CloseForm()
        {
            FileUtil.DelDir(".\\temp");
            Thread.Sleep(1000);
            try
            {
                this.Invoke(new Action(() =>
                {
                    this.Close();
                }));
            }
            catch { }
        }

        private void Client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (!e.Cancelled)
            {
                if (e.Error != null)
                {
                    var webError = e.Error as WebException;
                    if (webError != null)
                    {
                        var response = (HttpWebResponse)webError.Response;
                        if (response != null && (response.StatusCode == HttpStatusCode.NotModified || response.StatusCode == HttpStatusCode.NotFound))
                        {
                            Result = DownloadResult.NoNeed;
                            wh.Set();
                            return;
                        }
                    }
                    if (webError.InnerException != null)
                    {
                        var sockError = webError.InnerException as SocketException;
                        if (sockError != null && sockError.SocketErrorCode == SocketError.ConnectionRefused)
                        {
                            Result = DownloadResult.Error;
                            wh.Set();
                            return;
                        }
                    }
                }
                else
                {
                    try
                    {
                        var tempFile = e.UserState as TempFile;
                        File.Copy(tempFile.TempFileName, tempFile.FileName + ".update", true);
                        File.Delete(tempFile.TempFileName);
                        Result = DownloadResult.Success;
                        wh.Set();
                        return;
                    }
                    catch (Exception ex)
                    {
                        Result = DownloadResult.Error;
                        wh.Set();
                        return;
                    }
                }
            }
            Result = DownloadResult.Error;
            wh.Set();
            return;
        }

        private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            try
            {
                this.Invoke(new Action(() =>
                {
                    this.label1.Text = e.ProgressPercentage + "% ( " + e.BytesReceived / 1024 + " KB / " + e.TotalBytesToReceive / 1024 + " KB )";
                    this.progressBar1.Value = e.ProgressPercentage;
                }));
            }
            catch { }
        }

        public DownloadForm(string dir, string urlFormat, string[] files) : this()
        {
            this.dir = dir;
            this.urlfmt = urlFormat;
            this.files = files;
            this.label2.Text = "第1个/共" + files.Length + "个 " + files[0];
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        public class TempFile
        {
            public TempFile(string tempFileName, string fileName)
            {
                TempFileName = tempFileName;
                this.FileName = fileName;
            }

            public string TempFileName { get; set; }
            public string FileName { get; set; }
        }

        public enum DownloadResult
        {
            Error,
            Success,
            NoNeed
        }
    }
}
